using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Kinect;

namespace LearningBubbles
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        static GraphicsDeviceManager graphics;
        private static SpriteFont font;
        private static SpriteFont bubbleFont;
        private static BubbleObservable bo = new BubbleObservable();
        private static SpriteFont endScreenFont;

        private static int assNr;

        private World world;
        public static Random random = new Random();
        

        //test
        //private MouseControl mc = new MouseControl();

        public static GraphicsDeviceManager Graphics
        {
            get { return graphics; }
            set { graphics = value; }
        }
        SpriteBatch spriteBatch;
        KinectControl kinectControl = new KinectControl();

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            graphics.PreferredBackBufferWidth = 960;
            graphics.PreferredBackBufferHeight = 480;
        }      

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here
            KinectSensor.KinectSensors.StatusChanged += new EventHandler<StatusChangedEventArgs>(kinectControl.KinectSensors_StatusChanged);
            kinectControl.DiscoverKinectSensor();

            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            Textures.KinectRGBVideo = new Texture2D(GraphicsDevice, 640, 480);
            font = Content.Load<SpriteFont>("SpriteFont1");
            Textures.Bitmap1 = Content.Load<Texture2D>("Bitmap1");
            Textures.ElementTexture = Content.Load<Texture2D>("bubble1");
            bubbleFont = Content.Load<SpriteFont>("bubbleFont");
            Textures.PortalTex = Content.Load<Texture2D>("Portal1");
            Textures.HandLeft = Content.Load<Texture2D>("handleft");
            Textures.HandRight = Content.Load<Texture2D>("handright");
            Textures.HandLeftGrab = Content.Load<Texture2D>("handleftgrab");
            Textures.HandRightGrab = Content.Load<Texture2D>("handrightgrab");
            endScreenFont = Content.Load<SpriteFont>("endScreen");
        }

        protected void InitializeGame()
        {

            assNr = Menu.Ass.id;
            Menu.MenuStarted = false;
            gameStarted = true;
            world = new World(assNr);
            Gui.LoadGui(graphics, Gui.GuiPosition, world, this, bo);
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
            kinectControl.KinectSensor.Stop();
            kinectControl.KinectSensor.Dispose();
        }

        private KeyboardState oldState;

        protected void UpdateKeyboard()
        {
            KeyboardState newState = Keyboard.GetState();
            if (newState.IsKeyDown(Keys.Right))
            {
                if(!oldState.IsKeyDown(Keys.Right))
                    Menu.Pointer = (Menu.Pointer+1)%Menu.Asses.Count;
            }
            else if (newState.IsKeyDown(Keys.Left))
            {
                if (!oldState.IsKeyDown(Keys.Left))
                {
                    Menu.Pointer = (Menu.Pointer + 1) % Menu.Asses.Count;
                }
            }
            else if (newState.IsKeyDown(Keys.Enter))
            {
                if(!oldState.IsKeyDown(Keys.Enter))
                    InitializeGame();
            }
            oldState = newState;
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            // TODO: Add your update logic here
            if (gameStarted)
            {
                Gui.ProgressBar.value = world.Current1;
                world.Update(gameTime, kinectControl, bo);
                //test
                //mc.updateMouse();
            }
            else if(Menu.MenuStarted)
            {
                Menu.UpdatePointer();
                UpdateKeyboard();
            }


            base.Update(gameTime);
        }

        bool gameStarted = false;

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            // TODO: Add your drawing code here

            spriteBatch.Begin();
            if (gameStarted)
            {
                spriteBatch.Draw(Textures.KinectRGBVideo, new Rectangle(0, 0, 640, 480), Color.White);

                DrawTests(spriteBatch);

                DrawGame(spriteBatch);

                spriteBatch.Draw(Textures.GuiBackGround, new Rectangle(
                        (int)Gui.GuiPosition.X,
                        (int)Gui.GuiPosition.Y,
                        Textures.GuiBackGround.Width,
                        Textures.GuiBackGround.Height),
                    Color.White);

                Gui.ProgressBar.Draw(spriteBatch);
                Gui.Textbox.Draw(spriteBatch);

                foreach (Word item in world.CurrentElements)
                {
                    spriteBatch.Draw(Textures.ElementTexture, GetCorrectTexturePosition(item.Position, Textures.ElementTexture), Color.White);
                    spriteBatch.DrawString(bubbleFont, item.Value.ToString(), GetCorrectFontPosition(item.Position, bubbleFont, item.Value.ToString()), Color.Black);
                }

                //Texture2D rectTex = new Texture2D(graphics.GraphicsDevice, (int)kinectControl.rect.Width, (int)kinectControl.rect.Height, false, SurfaceFormat.Color);

                //Color[] color = new Color[kinectControl.rect.Width * kinectControl.rect.Height];
                //for (int i = 0; i < color.Length; i++)
                //{
                //    color[i] = Color.Red;
                //}
                //rectTex.SetData(color);

                //spriteBatch.Draw(rectTex, kinectControl.rect, Color.Red);

                spriteBatch.Draw(Textures.PortalTex, GetCorrectTexturePosition(new Vector2(world.Portal.x, world.Portal.y), Textures.PortalTex), Color.White);

                if (world.Completed)
                {
                    spriteBatch.DrawString(endScreenFont, GetCorrectStatus(), new Vector2(Textures.KinectRGBVideo.Width / 2, Textures.KinectRGBVideo.Height / 2), Color.Black);
                }
            }
            else
            {
                spriteBatch.DrawString(font,
                    Menu.Ass.assName.ToString(),
                    new Vector2(graphics.PreferredBackBufferWidth / 2, graphics.PreferredBackBufferHeight / 2),
                    Color.Black);
            }
            spriteBatch.End();
            base.Draw(gameTime);
        }

        public string GetCorrectStatus()
        {
            int correct = 0;
            for(int i = 0; i < world.Assignment.ElementStrings.Count; i++)
            {
                string s1 = world.Players[0].CollectedElements.ElementAt(i).Value.ToString();
                string s2 = world.Assignment.ElementStrings.ElementAt(i);
                if (s1.Equals(s2))
                {
                    correct++;
                }
            }
            return "" + correct + "/" + world.Players[0].CollectedElements.Count;
        }

        public void DrawTests(SpriteBatch spriteBatch)
        {
            spriteBatch.DrawString(font, kinectControl.ConnectedStatus
                    + " "
                    + PlayerData.LHandDepth[0]
                    + " - "
                    + PlayerData.RHandDepth[0]
                    + " Lhandgrabbing = "
                    + world.Players[0].Hands[0].HandInteracts, new Vector2(20, 80), Color.LightBlue);
            //spriteBatch.Draw(Textures.Bitmap1, GetCorrectHandTexturePosition(kinectControl.LHandPosition, 0), Color.White);
            //spriteBatch.Draw(Textures.Bitmap1, GetCorrectHandTexturePosition(kinectControl.RHandPosition, 0), Color.White);
            //spriteBatch.Draw(Textures.Bitmap1, GetCorrectHandTexturePosition(new Vector2[] {kinectControl.lWristColorPoint1}, 0), Color.White);
            //spriteBatch.DrawString(font, "hand " + PlayerData.HandPosition[0, 0].X + "," + PlayerData.HandPosition[0, 0].Y, GetCorrectFontPosition(PlayerData.HandPosition[0, 0], font, "hand"), Color.White);
            //spriteBatch.DrawString(font, "wrist", GetCorrectFontPosition(kinectControl.lWristColorPoint1, font, "wrist"), Color.White);
            //spriteBatch.DrawString(font, "lhanddepth " + kinectControl.lHandDepthPos, GetCorrectFontPosition(kinectControl.lHandDepthPos, font, "lhanddepth"), Color.White);
            //spriteBatch.DrawString(font, "offset", GetCorrectFontPosition(new Vector2(kinectControl.lHandOffsetPos.X, kinectControl.lHandOffsetPos.Y), font, "offset"), Color.White);
            //spriteBatch.Draw(Textures.Bitmap1, GetCorrectTexturePosition(PlayerData.HandPosition[0,0]), Color.White);
        }

        public void DrawGame(SpriteBatch spriteBatch)
        {
            if (PlayerData.HandGrabs[0, 0] == true)
            {
                spriteBatch.Draw(Textures.HandLeftGrab, GetCorrectTexturePosition(PlayerData.HandPosition[0, 0], Textures.HandLeftGrab), Color.White);
            }
            else spriteBatch.Draw(Textures.HandLeft, GetCorrectTexturePosition(PlayerData.HandPosition[0, 0], Textures.HandLeft), Color.White);
            if(PlayerData.HandGrabs[1,0] == true) spriteBatch.Draw(Textures.HandRightGrab, GetCorrectTexturePosition(PlayerData.HandPosition[1, 0], Textures.HandRightGrab), Color.White);
            else spriteBatch.Draw(Textures.HandRight, GetCorrectTexturePosition(PlayerData.HandPosition[1, 0], Textures.HandRight), Color.White);

        }

        private Vector2 GetCorrectFontPosition(Vector2 p, SpriteFont f, string s)
        {
            Vector2 newPos = new Vector2();
            newPos.X = p.X - (f.MeasureString(s).X) / 2;
            newPos.Y = p.Y - (f.MeasureString(s).Y) / 2;
            return newPos;
        }

        private Vector2 GetCorrectTexturePosition(Vector2 hp, Texture2D tex)
        {
            Vector2 newPos = new Vector2();
            newPos.X = hp.X - (tex.Width)/2;
            newPos.Y = hp.Y - (tex.Height)/2;
            return newPos;
        }
    }
}
